use super::{basecmd::BaseCmd, get_exec_path};
use crate::{
    config::CONTEXT,
    global::{DpmError, RespVO},
};
use async_trait::async_trait;
use rcmd_core::{
    clap::ArgMatches,
    log::{debug, error, info},
};
use serde::Serialize;

struct AddRuntime<'r> {
    runtime_name: &'r str,
    runtime_ver: &'r str,
}

#[derive(Serialize)]
struct Runtime<'r> {
    runtime: &'r str,
    ver_str: &'r str,
}

impl<'r> AddRuntime<'r> {
    fn new(_: &str, runtime_name: &'r str, runtime_ver: &'r str) -> Self {
        AddRuntime {
            runtime_name,
            runtime_ver: runtime_ver,
        }
    }

    pub async fn api_add_runtime<'a>(name: &'a str, ver: &'a str) -> surf::Result<RespVO<()>> {
        let _ = if ver.len() > 0 { ver } else { "+" };
        let api_url = format!(
            "{uri_base}/api/dpm/add_runtime",
            uri_base = CONTEXT.uri_base
        );

        debug!("api req->\n{}", api_url);
        let n_r = Runtime {
            runtime: name,
            ver_str: ver,
        };
        let ret = surf::put(api_url)
            .body_json(&n_r)
            .unwrap()
            .recv_json::<RespVO<()>>()
            .await;
        return ret;
    }
}

#[async_trait]
impl BaseCmd for AddRuntime<'_> {
    async fn run(&self) -> Result<(), DpmError> {
        let r = AddRuntime::api_add_runtime(&self.runtime_name, &self.runtime_ver).await;
        if let Err(err) = r {
            return Err(DpmError::ApiFailed(format!(
                "api to insert record into db failed!!\n{}",
                err.to_string()
            )));
        } else {
            let resp = r.unwrap();
            if resp.code != 0 {
                return Err(DpmError::ApiFailed(resp.msg));
            }
        }
        info!("suc！");
        Ok(())
    }
}

pub async fn handle(subm: &ArgMatches) {
    let p = get_exec_path();
    let r_name = subm.get_one::<String>("name").unwrap();
    let r_ver = subm.get_one::<String>("ver").unwrap();
    let cmd = &AddRuntime::new(p.as_str(), &r_name, &r_ver);
    cmd.run().await.unwrap_or_else(|e| {
        error!("{}", e.to_string().as_str());
    });
}
